/**
 * Copyright (C) 2016 Robinhood Markets, Inc.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.jinatonic.confetti;

import com.github.jinatonic.confetti.confetto.Confetto;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ComponentParent;
import ohos.agp.render.Canvas;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

import java.util.List;

/**
 * A helper temporary view that helps render the confetti. This view will attach itself to the
 * view root, perform the animation, and then once all of the confetti has completed its animation,
 * it will automatically remove itself from the parent.
 */
public class ConfettiView extends Component implements Component.DrawTask, Component.TouchEventListener {
    private List<Confetto> confetti;
    private boolean terminated;

    private boolean touchEnabled;
    private Confetto draggedConfetto;

    public static ConfettiView newInstance(Context context) {
        final ConfettiView confettiView = new ConfettiView(context, null);
        confettiView.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT));

        return confettiView;
    }

    public ConfettiView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init();
    }

    private void init() {
        addDrawTask(this);
        setTouchEventListener(this);
    }

    /**
     * Sets the list of confetti to be animated by this view.
     *
     * @param confetti the list of confetti to be animated.
     */
    public void bind(List<Confetto> confetti) {
        this.confetti = confetti;
    }

    /**
     * setTouchEnabled
     *
     * @param touchEnabled whether or not to enable touch
     * @see ConfettiManager#setTouchEnabled(boolean)
     */
    public void setTouchEnabled(boolean touchEnabled) {
        this.touchEnabled = touchEnabled;
    }

    /**
     * Terminate the current running animation (if any) and remove this view from the parent.
     */
    public void terminate() {
        final ComponentParent parent = getComponentParent();
        if (parent != null && parent instanceof ComponentContainer) {
            final ComponentContainer vg = (ComponentContainer) parent;
            vg.removeComponent(this);
        }
        invalidate();
    }

    /**
     * Reset the internal state of this view to allow for a new confetti animation.
     */
    public void reset() {
        this.terminated = false;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (!terminated) {
            canvas.save();
            for (Confetto confetto : this.confetti) {
                confetto.draw(canvas);
            }
            canvas.restore();
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        boolean handled = false;
        if (touchEnabled) {
            switch (touchEvent.getAction()) {
                case TouchEvent.PRIMARY_POINT_DOWN:
                    for (Confetto confetto : confetti) {
                        if (confetto.onTouchDown(touchEvent, component)) {
                            draggedConfetto = confetto;
                            handled = true;
                            break;
                        }
                    }
                case TouchEvent.POINT_MOVE:
                    if (draggedConfetto != null) {
                        draggedConfetto.onTouchMove(touchEvent, component);
                        handled = true;
                    }
                    break;
                case TouchEvent.PRIMARY_POINT_UP:
                case TouchEvent.CANCEL:
                    if (draggedConfetto != null) {
                        draggedConfetto.onTouchUp(touchEvent, component);
                        draggedConfetto = null;
                        handled = true;
                    }
                    break;
            }
        }

        return handled;
    }
}
